2. 쿠버네티스 개요1
3.1. 쿠버네티스의 특징
3.1.1. 파일을 사용한 선언적 관리
선언적 관리란?
쿠버네티스의 주요 특징은 선언적으로 애플리케이션을 관리할 수 있다는 것
- 선언적 관리(Declarative Management): "원하는 최종 상태"를 정의하면 시스템이 자동으로 그 상태를 유지하는 방식
- 명령형(Imperative): 수행할 작업을 단계별로 직접 명령하는 방식. 예: "컨테이너를 생성하라"
- 선언형(Declarative): 원하는 결과 상태만 선언하는 방식. 예: "컨테이너가 3개 있어야 한다"
선언적 관리 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[명령형 (Imperative)]
"어떻게(How)"를 명령
├─ 컨테이너 3개 생성하라
├─ 포트 80을 열어라
└─ 볼륨을 연결하라
문제점: 상태 추적 어려움, 재현 어려움
vs
[선언형 (Declarative)]
"무엇을(What)"을 선언
├─ 컨테이너는 3개여야 함
├─ 포트 80이 열려있어야 함
└─ 볼륨이 연결되어 있어야 함
장점: 상태 자동 유지, Git 버전 관리 가능
매니페스트 파일 (Manifest):
쿠버네티스에서 애플리케이션의 이상적인 상태를 YAML 또는 JSON 형식의 파일로 선언
- 매니페스트(Manifest): Kubernetes 리소스의 원하는 상태를 정의하는 YAML 또는 JSON 파일
- YAML: 사람이 읽기 쉬운 데이터 직렬화 형식. 들여쓰기로 계층 구조 표현
- replicas: 동시에 실행할 Pod 복제본의 개수
매니페스트 파일 구조:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[매니페스트 파일]
│
├─ 컨테이너 개수
│ └─ replicas: 3
│
├─ 배포 형식
│ └─ kind: Deployment
│
├─ 이미지 정보
│ └─ image: nginx:1.21
│
├─ 네트워크 설정
│ └─ ports, services
│
└─ 스토리지 설정
└─ volumes, persistentVolumes
선언적 관리의 장점:
파일 기반 관리 장점:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Git 버전 관리
│
├─ 변경 이력 추적
├─ 롤백 용이
└─ 팀 협업 가능
↓
재현 가능성
│
├─ 동일 환경 구축
├─ 개발/스테이징/프로덕션 일관성
└─ 장애 복구 신속
↓
자동화
│
├─ CI/CD 파이프라인 통합
├─ GitOps 워크플로우
└─ Infrastructure as Code (IaC)
- CI/CD(Continuous Integration/Continuous Delivery): 코드 변경을 자동으로 빌드, 테스트, 배포하는 소프트웨어 개발 방식
- GitOps: Git 저장소를 단일 진실 공급원(Single Source of Truth)으로 사용하여 인프라와 애플리케이션을 관리하는 방식
- IaC(Infrastructure as Code): 인프라 구성을 코드로 정의하고 관리하는 방식. 재현성과 버전 관리 가능
3.1.2. 광범위한 배포 형식 지원
다양한 워크로드 타입:
쿠버네티스는 컨테이너와 관련된 다양한 배포 형식을 지원
- 워크로드(Workload): 쿠버네티스에서 실행되는 애플리케이션의 유형. Deployment, StatefulSet, DaemonSet, Job 등
- Stateless: 상태를 저장하지 않는 애플리케이션. 어떤 인스턴스가 요청을 처리해도 결과 동일
- Stateful: 상태를 유지해야 하는 애플리케이션. 데이터베이스처럼 영구 저장소와 고유 식별자 필요
쿠버네티스 워크로드 타입:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Stateless 애플리케이션]
│
Deployment
├─ 웹 서버 (nginx, Apache)
├─ API 서버
└─ 정적 마이크로서비스
특징: 데이터 영구 보존 불필요
[Stateful 애플리케이션]
│
StatefulSet
├─ 데이터베이스 (MySQL, PostgreSQL)
├─ 메시지 큐 (Kafka, RabbitMQ)
└─ 분산 스토리지
특징: 고유 식별자, 영구 스토리지 필요
[데몬 프로세스]
│
DaemonSet
├─ 로그 수집 (Fluentd)
├─ 모니터링 (Prometheus Node Exporter)
└─ 네트워크 플러그인
특징: 모든 노드에서 실행
[배치 작업]
│
Job / CronJob
├─ 데이터 백업
├─ ETL 작업
└─ 정기 스크립트 실행
특징: 완료 후 종료, 스케줄 실행
- StatefulSet(스테이트풀셋): 상태 유지가 필요한 애플리케이션을 위한 컨트롤러. 고유한 네트워크 ID와 영구 스토리지 제공
- DaemonSet(데몬셋): 클러스터의 모든(또는 일부) 노드에 Pod를 하나씩 실행하는 컨트롤러
- Job: 한 번 실행 후 완료되는 배치 작업을 관리하는 컨트롤러
- CronJob: Job을 주기적으로 스케줄링하여 실행하는 컨트롤러. Linux cron과 유사
자동화된 관리 기능:
쿠버네티스 자동 관리:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[자동 복구 (Self-Healing)]
│
├─ 컨테이너 크래시 감지 → 자동 재시작
├─ 노드 장애 감지 → 다른 노드로 재배치
└─ Health Check 실패 → Pod 교체
↓
[자동 스케일링 (Auto-Scaling)]
│
├─ HPA (Horizontal Pod Autoscaler)
│ └─ CPU/메모리 사용률 기반 Pod 수 조정
│
├─ VPA (Vertical Pod Autoscaler)
│ └─ 리소스 요구량 자동 조정
│
└─ Cluster Autoscaler
└─ 노드 수 자동 조정
↓
[롤링 업데이트 (Rolling Update)]
│
├─ 무중단 배포
├─ 점진적 업데이트
└─ 자동 롤백 (실패 시)
- Self-Healing(자동 복구): 컨테이너 장애 시 자동으로 재시작하고, 노드 장애 시 다른 노드로 Pod를 재배치하는 기능
- HPA(Horizontal Pod Autoscaler): CPU/메모리 사용률 등 메트릭에 따라 Pod 수를 자동으로 조절
- VPA(Vertical Pod Autoscaler): Pod의 CPU/메모리 요청량을 자동으로 조절
- Rolling Update(롤링 업데이트): 서비스 중단 없이 점진적으로 새 버전을 배포하는 방식
- 롤백(Rollback): 배포 실패 시 이전 버전으로 되돌리는 작업
3.1.3. 확장성이 뛰어난 아키텍처
쿠버네티스 확장 메커니즘:
쿠버네티스 확장 아키텍처:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[API 서버 (kube-apiserver)]
│
HTTP REST API 제공
│
├─ 클러스터 상태 조회
├─ 리소스 생성/수정/삭제
└─ 이벤트 모니터링 (Watch)
↓
[컨트롤러 (Controller)]
│
API 감시 + 상태 조정
│
├─ 기본 컨트롤러
│ ├─ Deployment Controller
│ ├─ ReplicaSet Controller
│ └─ Service Controller
│
└─ 커스텀 컨트롤러
├─ Operator Pattern
├─ 서드파티 컨트롤러
└─ 사용자 정의 컨트롤러
↓
[커스텀 리소스 (CRD)]
│
API 확장
│
├─ 새로운 리소스 타입 정의
├─ 도메인 특화 객체 관리
└─ 커스텀 컨트롤러와 연동
- 컨트롤러(Controller): 클러스터 상태를 감시하고 현재 상태를 원하는 상태로 조정하는 컴포넌트
- Watch: API 서버의 리소스 변경을 실시간으로 감시하는 메커니즘
- CRD(Custom Resource Definition): 사용자가 새로운 리소스 타입을 정의할 수 있게 해주는 Kubernetes 확장 메커니즘
- Operator Pattern: CRD와 커스텀 컨트롤러를 조합하여 복잡한 애플리케이션을 자동 관리하는 패턴
확장 가능한 컴포넌트:
교체 가능한 컴포넌트:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[컨테이너 런타임]
├─ containerd (권장)
├─ CRI-O
└─ Docker Engine (deprecated)
[네트워크 플러그인 (CNI)]
├─ Calico
├─ Flannel
├─ Cilium
└─ Weave Net
[스토리지 플러그인 (CSI)]
├─ AWS EBS
├─ GCE Persistent Disk
├─ Azure Disk
└─ Ceph, NFS
[인그레스 컨트롤러]
├─ NGINX Ingress Controller
├─ Traefik
├─ HAProxy
└─ 클라우드 제공업체 LB
- CNI(Container Network Interface): 컨테이너 네트워킹을 위한 표준 인터페이스. Calico, Flannel, Cilium 등 다양한 플러그인 존재
- CSI(Container Storage Interface): 컨테이너 스토리지를 위한 표준 인터페이스. 클라우드 스토리지와 쉽게 연동
- Ingress(인그레스): 클러스터 외부에서 내부 서비스로의 HTTP/HTTPS 라우팅을 관리하는 리소스
- Ingress Controller: Ingress 리소스의 규칙을 실제로 구현하는 컨트롤러. NGINX, Traefik 등
CNCF 생태계:
쿠버네티스는 Cloud Native Computing Foundation (CNCF)을 중심으로 개발된 오픈소스 프로젝트
CNCF 프로젝트 생태계:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[서비스 메시]
├─ Istio
├─ Linkerd
└─ Consul
[모니터링/관찰성]
├─ Prometheus
├─ Grafana
├─ Jaeger
└─ Fluentd
[보안]
├─ Falco
├─ Open Policy Agent (OPA)
└─ cert-manager
[CI/CD]
├─ Argo CD
├─ Flux
└─ Tekton
[클러스터 관리]
├─ Rancher
├─ Kubeadm
└─ kops
- CNCF(Cloud Native Computing Foundation): 클라우드 네이티브 기술의 발전을 위한 오픈소스 재단. Kubernetes 호스팅
- 서비스 메시(Service Mesh): 마이크로서비스 간 통신을 관리하는 인프라 계층. 트래픽 관리, 보안, 관찰성 제공
- Prometheus: 메트릭 수집과 알림을 위한 오픈소스 모니터링 시스템
- Grafana: 메트릭 데이터를 시각화하는 대시보드 도구
- cert-manager: Kubernetes에서 TLS 인증서를 자동으로 관리하는 도구
3.2. 쿠버네티스 클러스터와 kubectl
쿠버네티스 클러스터 아키텍처
클러스터 전체 구조:

주요 컴포넌트 설명:
| 컴포넌트 | 역할 | 위치 |
|---|---|---|
| kube-apiserver | 클러스터 관리 API 제공 | Control Plane |
| etcd | 클러스터 상태 데이터 저장 | Control Plane |
| kube-scheduler | Pod를 적절한 노드에 배치 | Control Plane |
| kube-controller | 리소스 상태 감시 및 조정 | Control Plane |
| kubelet | 노드에서 Pod 실행 관리 | Worker Node |
| kube-proxy | 네트워크 라우팅 및 로드밸런싱 | Worker Node |
| Container Runtime | 실제 컨테이너 실행 (containerd, CRI-O) | Worker Node |
- kubelet(큐블릿): 각 워커 노드에서 실행되며, Pod의 컨테이너가 정상 실행되도록 관리하는 에이전트
- kube-proxy(큐브 프록시): 각 노드에서 네트워크 규칙을 관리하고 서비스로의 트래픽을 Pod로 전달
- Container Runtime(컨테이너 런타임): 컨테이너를 실제로 실행하는 소프트웨어. containerd, CRI-O 등
kubectl 명령줄 도구
kubectl이란?
쿠버네티스 클러스터를 조작하고 정보를 조회하기 위한 명령줄 인터페이스 (CLI)
kubectl 작동 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[사용자]
│
│ kubectl create deployment nginx --image=nginx
↓
[kubectl CLI]
│
│ HTTP REST API 요청 생성
│ - POST /apis/apps/v1/namespaces/default/deployments
↓
[kube-apiserver]
│
│ 요청 처리
│ - 인증/인가
│ - etcd에 저장
↓
[컨트롤러]
│
│ API 변경 감지 (Watch)
│ - Deployment Controller 동작
│ - ReplicaSet 생성
↓
[Scheduler]
│
│ Pod 스케줄링
│ - 적절한 노드 선택
↓
[Kubelet (Worker Node)]
│
│ Pod 실행
│ - 컨테이너 생성
3.2.1. kubectl 기본 사용법
명령형 방식 (Imperative)
Deployment 생성:
# Deployment 생성
kubectl create deployment nginx-deployment --image=nginx
# 단축어 사용 (alias k='kubectl' 설정 후)
k create deployment nginx-deployment --image=nginx
# 자동완성 사용
k cr<Tab> de<Tab> nginx-deployment --image=nginx
출력 예시:
deployment.apps/nginx-deployment created
Deployment 상태 확인:
# Deployment 목록 조회
kubectl get deployments
# 축약형
kubectl get deploy
# 더 많은 정보 출력
kubectl get deployments -o wide
출력 예시:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 1/1 1 1 10s
Pod 상태 확인:
# Pod 목록 조회
kubectl get pods
# 축약형
kubectl get po
출력 예시:
NAME READY STATUS RESTARTS AGE
nginx-deployment-7d64f8d4c9-xxxxx 1/1 Running 0 15s
리소스 삭제:
# Deployment 삭제
kubectl delete deployment nginx-deployment
출력 예시:
deployment.apps "nginx-deployment" deleted
선언형 방식 (Declarative)
매니페스트 파일 작성:
파일명: nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
매니페스트 구조 설명:
매니페스트 필드:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
apiVersion: apps/v1
└─ 사용할 API 버전
kind: Deployment
└─ 리소스 타입 (Deployment, Service, Pod 등)
metadata:
└─ 리소스 메타정보
├─ name: 리소스 이름
├─ labels: 레이블 (key-value)
└─ namespace: 네임스페이스
spec:
└─ 리소스 상세 사양
├─ replicas: Pod 개수
├─ selector: Pod 선택 기준
└─ template: Pod 템플릿
├─ metadata: Pod 메타정보
└─ spec: Pod 사양
├─ containers: 컨테이너 목록
├─ volumes: 볼륨 목록
└─ nodeSelector: 노드 선택
매니페스트 적용:
# 매니페스트 파일 적용
kubectl apply -f nginx-deployment.yaml
# 여러 파일 동시 적용
kubectl apply -f deployment.yaml -f service.yaml
# 디렉터리 전체 적용
kubectl apply -f ./manifests/
출력 예시:
deployment.apps/nginx-deployment created
리소스 상태 확인:
# 적용된 Deployment 확인
kubectl get deployment nginx-deployment
# YAML 형식으로 출력
kubectl get deployment nginx-deployment -o yaml
# JSON 형식으로 출력
kubectl get deployment nginx-deployment -o json
# 상세 정보 확인
kubectl describe deployment nginx-deployment
3.2.2. 쿠버네티스 자동 관리
자동 복구 (Self-Healing):
쿠버네티스는 적용한 설정에 따라 클러스터 상태를 자동으로 유지
자동 복구 시나리오:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[상황 1: Pod 크래시]
│
컨테이너 비정상 종료
↓
kubelet 감지
↓
컨테이너 자동 재시작
↓
상태 복구
[상황 2: 노드 장애]
│
Node 1 다운
├─ Pod A (실행 중)
└─ Pod B (실행 중)
↓
Control Plane 감지 (약 5분)
↓
Node 2, 3으로 Pod 재배치
├─ Pod A → Node 2
└─ Pod B → Node 3
↓
상태 복구
[상황 3: replicas 불일치]
│
설정: replicas: 3
현재: 실행 중인 Pod 2개
↓
ReplicaSet Controller 감지
↓
부족한 1개 Pod 생성
↓
상태 복구
실습 예시:
# replicas 3으로 설정
kubectl scale deployment nginx-deployment --replicas=3
# Pod 확인 (3개 실행 중)
kubectl get pods
# Pod 하나 강제 삭제
kubectl delete pod nginx-deployment-xxxxx
# 즉시 새로운 Pod 생성됨 (자동 복구)
kubectl get pods
출력 예시:
# 삭제 전
NAME READY STATUS RESTARTS AGE
nginx-deployment-7d64f8d4c9-abc12 1/1 Running 0 2m
nginx-deployment-7d64f8d4c9-def34 1/1 Running 0 2m
nginx-deployment-7d64f8d4c9-ghi56 1/1 Running 0 2m
# 삭제 후 (자동으로 새 Pod 생성됨)
NAME READY STATUS RESTARTS AGE
nginx-deployment-7d64f8d4c9-def34 1/1 Running 0 2m
nginx-deployment-7d64f8d4c9-ghi56 1/1 Running 0 2m
nginx-deployment-7d64f8d4c9-jkl78 1/1 Running 0 5s
3.2.3. 명령형 vs 선언형 비교
두 방식의 차이:
| 항목 | 명령형 (Imperative) | 선언형 (Declarative) |
|---|---|---|
| 명령어 | create, run, expose, scale |
apply |
| 특징 | "어떻게" 할지 지시 | "무엇을" 원하는지 선언 |
| 버전 관리 | 어려움 | Git으로 쉽게 관리 |
| 재현성 | 낮음 | 높음 |
| 학습 난이도 | 쉬움 | 보통 |
| 프로덕션 | 비권장 | 권장 |
| 용도 | 빠른 테스트, 디버깅 | 프로덕션 배포, 자동화 |
권장 워크플로우:
개발 워크플로우:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[개발/테스트 단계]
│
명령형 방식으로 빠른 실험
├─ kubectl run nginx --image=nginx
├─ kubectl expose pod nginx --port=80
└─ 빠른 반복 테스트
↓
[확정 후 매니페스트 작성]
│
선언형 파일로 정리
├─ deployment.yaml
├─ service.yaml
└─ Git에 커밋
↓
[프로덕션 배포]
│
매니페스트 기반 배포
├─ kubectl apply -f ./manifests/
├─ GitOps 워크플로우
└─ 자동 배포 파이프라인
3.3. 쿠버네티스의 기본 배포 단위: Pod
Pod란?
도커 vs 쿠버네티스 배포 단위:
배포 단위 비교:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Docker]
기본 단위: 컨테이너
├─ 컨테이너 1개 = 애플리케이션 1개
└─ 개별 관리
vs
[Kubernetes]
기본 단위: Pod
├─ Pod 1개 = 컨테이너 1개 이상
├─ 관련 컨테이너 그룹화
└─ 통합 관리
쿠버네티스에서 애플리케이션은 도커와 마찬가지로 컨테이너로 실행되지만, 가장 기본적인 배포 단위는 Pod (파드)
Pod의 정의:
- 하나 이상의 컨테이너를 묶어서 관리하는 배포 단위
- Pod 1개에 컨테이너 1개만 포함 가능 (일반적)
- Pod 1개에 여러 컨테이너 포함 가능 (밀접한 관계)
3.3.1. Pod와 컨테이너
Pod 내부 구조:
Pod 구조:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─────────────────────────────────────┐
│ Pod (10.1.0.5) │ ← Pod IP 주소
│ │
│ ┌────────────┐ ┌─────────────┐ │
│ │ Container1 │ │ Container2 │ │
│ │ (nginx) │ │ (alpine) │ │
│ │ │ │ │ │
│ │ Port: 80 │◄───┤ localhost │ │ ← localhost 통신
│ └─────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ └──────────┬───────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ 공유 볼륨 │ │ ← 볼륨 공유
│ │ (emptyDir) │ │
│ └───────────────────┘ │
│ │
└──────────────────────────────────────┘
│
│ 네트워크 통신
▼
다른 Pod (10.1.0.6)
Pod의 특징:
| 항목 | 설명 |
|---|---|
| 배포 위치 | 동일한 노드에 함께 배포 |
| 네트워크 | Pod마다 고유 IP 주소 할당 |
| 컨테이너 간 통신 | 동일 Pod 내 컨테이너는 localhost로 통신 |
| Pod 간 통신 | 각 Pod의 IP 주소로 통신 |
| 스토리지 | 볼륨을 컨테이너 간 공유 가능 |
멀티 컨테이너 Pod 예제
매니페스트 파일:
파일명: pod-example.yaml
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
# 컨테이너 1: nginx 웹 서버
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/
name: docroot
# 컨테이너 2: 데이터 생성
- name: alpine
image: alpine:3.18
command: ["sh"]
args:
- -euc
- |
for i in $(seq 1 10) ; do
echo '{"date": "'$(date)'"}' >> /mnt/date.json
sleep 3
done ; sleep infinity
volumeMounts:
- mountPath: /mnt/
name: docroot
# 컨테이너 간 공유 볼륨
volumes:
- name: docroot
emptyDir:
sizeLimit: 500Mi
emptyDir 볼륨이란?
- emptyDir: Pod가 노드에 할당될 때 생성되는 임시 볼륨. Pod 삭제 시 데이터도 함께 삭제
- 볼륨(Volume): Pod 내 컨테이너가 데이터를 저장하거나 공유할 수 있는 디렉터리
- volumeMounts: 컨테이너 내부의 어떤 경로에 볼륨을 마운트할지 지정
emptyDir 볼륨 동작 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Worker Node 호스트]
│
/var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~empty-dir/docroot/
│
├─ Pod 생성 시 자동으로 빈 디렉터리 생성
├─ Pod 내 모든 컨테이너가 동일 경로 공유
└─ Pod 삭제 시 볼륨 데이터도 함께 삭제
↓
[Pod 내부 마운트]
│
nginx 컨테이너: /usr/share/nginx/html/ → 호스트의 docroot 디렉터리
alpine 컨테이너: /mnt/ → 호스트의 docroot 디렉터리
│
└─ 동일한 호스트 디렉터리를 서로 다른 경로로 마운트
emptyDir 특징:
| 항목 | 설명 |
|---|---|
| 생성 시점 | Pod 생성 시 자동 생성 |
| 삭제 시점 | Pod 삭제 시 자동 삭제 (임시 저장소) |
| 저장 위치 | Worker Node의 /var/lib/kubelet/pods/ 아래 |
| 공유 범위 | 동일 Pod 내 모든 컨테이너 |
| 용도 | 임시 파일, 캐시, 컨테이너 간 데이터 전달 |
| 영구성 | 없음 (Pod 재시작 시 데이터 손실) |
볼륨 이름 (docroot):
docroot는 사용자가 정의한 볼륨 이름 (임의 지정 가능)volumes[].name과volumeMounts[].name이 일치해야 매핑됨- 관례적으로 웹 서버의 문서 루트(document root)를 의미
동작 방식:
멀티 컨테이너 Pod 동작:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Worker Node 호스트]
│
/var/lib/kubelet/pods/abc123/volumes/.../docroot/
│
↓
[alpine 컨테이너]
│
│ 타임스탬프 생성
│ echo '{"date": "..."}' >> /mnt/date.json
│ (실제로는 호스트의 docroot/date.json에 저장)
↓
[공유 볼륨 (docroot)]
│
│ 파일 공유
│ date.json 파일이 두 컨테이너에 동시 접근 가능
↓
[nginx 컨테이너]
│
│ HTTP 서버로 파일 공개
│ /usr/share/nginx/html/date.json 읽기
│ (실제로는 호스트의 docroot/date.json 읽기)
│ localhost:80/date.json
↓
[외부 접근]
│
│ Pod IP:80/date.json
실습 명령어:
# Pod 생성
kubectl apply -f pod-example.yaml
# Pod 확인
kubectl get pods
Windows (PowerShell):
# alpine 컨테이너에서 nginx로 접근 후 처음 3줄만 출력
kubectl exec -it example-pod -c alpine -- wget -qO - localhost:80/date.json | Select-Object -First 3
# 또는 더 간단하게
kubectl exec example-pod -c alpine -- wget -qO - localhost:80/date.json | Select-Object -First 3
macOS / Linux (Bash):
# alpine 컨테이너에서 nginx로 접근 후 처음 3줄만 출력
kubectl exec -it example-pod -c alpine -- wget -qO - localhost:80/date.json | head -n 3
# 또는
kubectl exec example-pod -c alpine -- wget -qO - localhost:80/date.json | head -3
출력 예시:
{"date": "Sat Jan 11 12:00:00 UTC 2026"}
{"date": "Sat Jan 11 12:00:03 UTC 2026"}
{"date": "Sat Jan 11 12:00:06 UTC 2026"}
명령어 옵션 상세 설명:
kubectl exec 명령어 분석:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
kubectl exec
└─ Pod 내부 컨테이너에서 명령 실행
-it
├─ -i (--stdin): 표준 입력(stdin)을 유지하여 대화형 실행
└─ -t (--tty): 터미널(TTY) 할당 (대화형 셸 사용 시 필수)
└─ 참고: 단순 명령 실행 시 -it 생략 가능
example-pod
└─ Pod 이름
-c alpine
├─ -c (--container): 컨테이너 이름 지정
└─ 멀티 컨테이너 Pod에서 필수 (단일 컨테이너면 생략 가능)
--
└─ kubectl 옵션과 컨테이너 내부 명령 구분
wget -qO - localhost:80/date.json
├─ wget: 파일 다운로드 도구
├─ -q (--quiet): 진행 상황 메시지 숨김
├─ -O - (--output-document=-): 표준 출력(stdout)으로 출력
└─ localhost:80/date.json: 다운로드 URL
| (파이프)
└─ 앞 명령의 출력을 뒤 명령의 입력으로 전달
Windows: Select-Object -First 3
└─ 처음 3줄만 선택하여 출력
Linux: head -n 3
└─ 처음 3줄만 출력 (-n 3 또는 -3)
Pod 삭제:
kubectl delete -f pod-example.yaml
참고:
- Pod 삭제 시 emptyDir 볼륨의 모든 데이터도 함께 삭제됨
- 영구 데이터 저장이 필요하면 PersistentVolume 사용 필요
Pod 디자인 패턴
1개 Pod에 여러 컨테이너를 배치하는 디자인 패턴:
Pod 디자인 패턴:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[사이드카 패턴 (Sidecar)]
┌─────────────────────────┐
│ Pod │
│ ┌────────┐ ┌────────┐ │
│ │ Main │ │Sidecar │ │
│ │ App │◄─┤ 로그 │ │
│ │ │ │ 수집 │ │
│ └────────┘ └────────┘ │
└─────────────────────────┘
용도:
├─ 로그 수집 (Fluentd)
├─ Git 동기화
└─ 모니터링 에이전트
[앰배서더 패턴 (Ambassador)]
┌─────────────────────────┐
│ Pod │
│ ┌────────┐ ┌────────┐ │
│ │ App │─►│ Proxy │ │
│ │ │ │ │─┼─► 외부 서비스
│ └────────┘ └────────┘ │
└─────────────────────────┘
용도:
├─ DB 프록시
├─ API 게이트웨이
└─ 서비스 메시 프록시
[어댑터 패턴 (Adapter)]
┌─────────────────────────┐
│ Pod │
│ ┌────────┐ ┌────────┐ │
│ │ App │─►│Adapter │─┼─► 표준화된 출력
│ │ │ │ │ │
│ └────────┘ └────────┘ │
└─────────────────────────┘
용도:
├─ 로그 형식 변환
├─ 메트릭 표준화
└─ 데이터 변환
패턴별 사용 사례:
| 패턴 | 설명 | 예시 |
|---|---|---|
| 사이드카 | 메인 컨테이너 기능 확장 | 로그 수집, Git 동기화 |
| 앰배서더 | 외부 서비스 접근을 대신 처리 | DB 프록시, 서비스 디스커버리 |
| 어댑터 | 출력 형식을 표준화하여 외부 제공 | 로그 포맷 변환, 메트릭 형식 통일화 |
- 사이드카 패턴(Sidecar Pattern): 메인 컨테이너를 보조하는 컨테이너를 같은 Pod에 배치. 로그 수집, 프록시 등에 활용
- 앰배서더 패턴(Ambassador Pattern): 외부 서비스와의 통신을 대리하는 컨테이너 배치. DB 연결 풀링 등
- 어댑터 패턴(Adapter Pattern): 메인 컨테이너의 출력을 표준 형식으로 변환하는 컨테이너 배치
3.3.2. Label과 Annotation
대규모 리소스 관리:
대규모 서비스에서는 Pod와 관리 대상이 수백 개 이상으로 증가하므로 그룹화 및 메타데이터 부여 필요
- Label(레이블): 리소스를 식별하고 그룹화하기 위한 키-값 쌍. Selector로 선택 가능
- Annotation(애너테이션): 리소스에 추가 메타데이터를 부여하는 키-값 쌍. Selector 사용 불가
- Selector(셀렉터): 레이블을 기준으로 리소스를 선택하는 쿼리 메커니즘
리소스 관리 메커니즘:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Label (레이블)]
│
키-값 쌍으로 리소스 식별
│
├─ app: nginx
├─ env: production
└─ tier: frontend
↓
[Selector (셀렉터)]
│
레이블 기반으로 리소스 선택
│
matchLabels:
app: nginx
↓
[리소스 그룹화]
│
선택된 Pod들을 하나의 Deployment로 관리
vs
[Annotation (애너테이션)]
│
키-값 쌍으로 추가 정보 부여
│
├─ kubernetes.io/change-cause: "Update to v2.0"
├─ prometheus.io/scrape: "true"
└─ description: "Production web server"
↓
Selector 사용 불가
↓
메타데이터 및 도구 설정용
Label vs Annotation:
| 항목 | Label (레이블) | Annotation (애너테이션) |
|---|---|---|
| 형식 | 키-값 쌍 | 키-값 쌍 |
| Selector | 사용 가능 | 사용 불가 |
| 용도 | 리소스 식별, 그룹화 | 메타데이터, 도구 설정 |
| 예시 | app: nginx, env: prod |
description: "...", build: "12" |
| 크기 제한 | 63자 (값) | 제한 없음 |
Deployment와 Selector의 관계
Deployment가 Selector를 사용하는 이유:
Deployment는 Pod를 직접 생성하지 않고, ReplicaSet을 통해 Pod를 관리함. Selector는 "어떤 Pod들을 내가 관리할 것인가"를 정의하는 핵심 메커니즘
Deployment와 Selector 동작:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Deployment]
│
spec:
replicas: 3
selector:
matchLabels:
app: nginx ← "app=nginx 레이블을 가진 Pod를 관리"
│
├─ Deployment Controller가 ReplicaSet 생성
│
↓
[ReplicaSet]
│
│ Deployment의 Selector 상속
│ selector: app=nginx
│
├─ "app=nginx" 레이블을 가진 Pod를 찾음
├─ 현재 개수 확인: 1개 존재
├─ 목표 개수: 3개 (replicas: 3)
└─ 부족한 2개 Pod 생성
↓
[Pod 생성]
│
template:
metadata:
labels:
app: nginx ← 생성되는 Pod에 자동으로 레이블 부여
│
└─ 3개의 Pod 모두 "app=nginx" 레이블 보유
↓
[지속적인 관리]
│
├─ Pod 1개 삭제됨 → ReplicaSet이 감지
├─ "app=nginx" 레이블을 가진 Pod 개수 확인: 2개
├─ 목표 개수 3개와 불일치
└─ 부족한 1개 자동 생성
실제 동작 예시:
상황 1: Pod 수동 삭제
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[현재 상태]
Pod A: labels: {app: nginx} ✓
Pod B: labels: {app: nginx} ✓
Pod C: labels: {app: nginx} ✓
→ 총 3개 (목표 3개 일치)
[사용자가 Pod B 삭제]
$ kubectl delete pod nginx-deployment-xxx-B
[ReplicaSet Controller 동작]
1. "app=nginx" 레이블을 가진 Pod 검색
2. 현재 개수: 2개 발견
3. 목표 개수: 3개 (replicas: 3)
4. → 새로운 Pod D 자동 생성 (labels: {app: nginx})
[최종 상태]
Pod A: labels: {app: nginx} ✓
Pod C: labels: {app: nginx} ✓
Pod D: labels: {app: nginx} ✓ (새로 생성)
→ 총 3개 복구
상황 2: 레이블 변경
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[현재 상태]
Pod A: labels: {app: nginx} ✓
Pod B: labels: {app: nginx} ✓
Pod C: labels: {app: nginx} ✓
[사용자가 Pod B의 레이블 변경]
$ kubectl label pod nginx-deployment-xxx-B app=web --overwrite
[ReplicaSet Controller 동작]
1. "app=nginx" 레이블을 가진 Pod 검색
2. 현재 개수: 2개 (Pod A, C만 해당)
3. 목표 개수: 3개
4. → 새로운 Pod D 자동 생성
[최종 상태]
Pod A: labels: {app: nginx} ✓ (관리됨)
Pod B: labels: {app: web} ✗ (관리 제외됨, 계속 실행)
Pod C: labels: {app: nginx} ✓ (관리됨)
Pod D: labels: {app: nginx} ✓ (새로 생성, 관리됨)
→ app=nginx: 3개, app=web: 1개
Selector의 핵심 역할:
| 역할 | 설명 |
|---|---|
| Pod 식별 | 수많은 Pod 중 어떤 것을 관리할지 식별 |
| 동적 관리 | 레이블이 일치하는 Pod 개수를 지속적으로 모니터링 |
| 자동 복구 | Pod가 삭제되면 Selector로 개수 확인 후 자동 생성 |
| 느슨한 결합 | Pod와 Deployment를 레이블로 연결 (직접 참조 없음) |
| 유연한 업데이트 | 레이블만 변경하면 관리 대상에서 제외 가능 |
Label 사용 예제
Deployment에서 Label 활용:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx # "app=nginx" 레이블을 가진 Pod를 관리
template:
metadata:
labels:
app: nginx # 생성되는 Pod에 레이블 부여
env: production
tier: frontend
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
Selector와 Label의 일치:
selector.matchLabels.app: nginx→ "app=nginx인 Pod를 찾아서 관리"template.metadata.labels.app: nginx→ "생성하는 Pod에 app=nginx 레이블 부여"- 이 두 값이 일치해야 Deployment가 자신이 생성한 Pod를 관리 가능
실습:
# Deployment 생성
kubectl apply -f nginx-deployment.yaml
# Pod 확인 (3개 생성됨)
kubectl get pods --show-labels
# Pod 하나 삭제
kubectl delete pod <pod-name>
# 즉시 새 Pod 생성 확인 (Selector 덕분에 자동 복구)
kubectl get pods --show-labels
Label 기반 조회:
# 특정 레이블을 가진 Pod 조회
kubectl get pods -l app=nginx
# 여러 레이블 조건
kubectl get pods -l app=nginx,env=production
# 레이블 표시
kubectl get pods --show-labels
# 레이블로 필터링하여 삭제
kubectl delete pods -l env=development
출력 예시:
NAME READY STATUS LABELS
nginx-deployment-7d64f8d4c9-abc12 1/1 Running app=nginx,env=production,tier=frontend
nginx-deployment-7d64f8d4c9-def34 1/1 Running app=nginx,env=production,tier=frontend
nginx-deployment-7d64f8d4c9-ghi56 1/1 Running app=nginx,env=production,tier=frontend
Label Selector 표현식:
Selector 연산자:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Equality-based (등호 기반)]
app = nginx # app이 nginx인 것
env != production # env가 production이 아닌 것
[Set-based (집합 기반)]
env in (prod, qa) # env가 prod 또는 qa인 것
tier notin (frontend) # tier가 frontend가 아닌 것
app # app 레이블이 존재하는 것
!version # version 레이블이 없는 것
Annotation 사용 예제
Deployment에 Annotation 추가:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
kubernetes.io/change-cause: "Update nginx to v1.25"
description: "Production web server for main site"
contact: "devops@example.com"
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9113"
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
Annotation 활용 예시:
# Annotation 확인
kubectl describe deployment nginx-deployment
# 롤아웃 히스토리 (change-cause annotation 활용)
kubectl rollout history deployment nginx-deployment
출력 예시:
REVISION CHANGE-CAUSE
1 Update nginx to v1.25
2 Update nginx to v1.26
3 Rollback to v1.25
참고 자료
공식 문서:
- Kubernetes 공식 문서: https://kubernetes.io/docs/
- Kubernetes API Reference: https://kubernetes.io/docs/reference/
- kubectl 치트시트: https://kubernetes.io/docs/reference/kubectl/cheatsheet/
커뮤니티:
- Kubernetes Slack: https://slack.k8s.io/
- CNCF 프로젝트: https://www.cncf.io/projects/
- Stack Overflow: https://stackoverflow.com/questions/tagged/kubernetes